home *** CD-ROM | disk | FTP | other *** search
- /*
- Biomorphs - by John Jeppson.
-
- This source code is in the public domain.
- Written in MPW C.
-
- This program is an MPW Tool which implements Biomorphs as
- described in "Computer Recreations" by A.K.Dewdney in
- Scientific American, July 1989.
-
- From the MPW Worksheet execute:
-
- Biomorph c.real c.imag top left bottom right
-
- where "c" is the required complex constant and "top", etc.
- are the components of the target rectangle on the complex
- plane. Our complex plane has the imaginary component
- increasing downward in the usual Macintosh fashion.
-
- After the biomorph is drawn you will hear a SysBeep. You
- may interrupt a partially completed drawing by clicking the
- mouse or pressing any key. You may not see any immediate
- effect, but the drawing will soon terminate with a double
- SysBeep at the end of the current vertical pass.
-
- You may print the completed biomorph by pressing "p".
-
- Return to the shell with the close box.
-
- The iterated generating function is supplied in the
- program function "generator". The tool must be recompiled
- to install a different generator.
-
- It is easiest to use the functions available in <Complex.h>.
- For example:
-
- complex generator(complex z) // z = z^3 + c
- {
- return ( cadd (cxpwri(z, 3), c) );
- }
-
- These built-in complex functions, however, are quite slow,
- so you may want to use your own formulae whenever possible,
- as is done in the program below.
-
-
-
- The article in Scientific American suggests:
-
- c: 0.5 + 0.0i
- bounds: -1.5, -1.5, 1.5, 1.5
- generator: z = z^3 + c
-
- NOTE: The program below uses this generator;
- from the MPW shell execute:
-
- Biomorph 0.5 0.0 -1.5 -1.5 1.5 1.5
-
-
-
- The spiky radiolarian actually illustrated in the Scientific
- American article is created by:
-
- c: 0.2 + 0.8i
- bounds: -10.0, -10.0, 10.0, 10.0
- generator: z = z^3 + c
-
-
- Try also:
-
- c: 0.2 + 0.8i
- bounds: -1.2, -1.2, 1.2, 1.2
- generator: z = z^5 + c
- use: cadd (cxpwri(z, 5), c)
-
-
-
- c: 0.5 + 0.8i
- bounds: 3.15, 2.2, 4.35, 3.4
- generator: z = sin(z) + z^2 + c
- use: cadd (cadd (csin(z), csquare(z)), c)
- */
-
- #include <Types.h>
- #include <Windows.h>
- #include <Memory.h>
- #include <Printing.h>
- #include <Fonts.h>
- #include <Resources.h>
- #include <OSUtils.h>
- #include <Math.h>
- #include <Complex.h>
- #include <StdLib.h>
-
-
- #define stepsX 100
- #define stepsY 100
-
- #define windowTop 40
- #define windowLeft 4
- #define windowHeight ( stepsY + 40 )
- #define windowWidth ( stepsX + 40 )
- #define windowTitle "\pBiomorphs"
-
- #define nil 0L
-
-
- typedef struct
- {
- extended top,left,bottom,right;
- } cRect;
-
-
- /**** globals ****/
-
- WindowPtr display;
- complex c;
- cRect target;
- extended incX, incY;
- short x0, y0;
- Boolean alreadyDrawn;
- BitMap offScreen;
-
-
-
- complex generator(complex z)
- // z = z^3 + c
- // (a+bi)^3 = a(a^2 - 3b^2) + b(3a^2 - b^2)i
- {
- complex n;
-
- n.re = z.re * ((z.re * z.re) - (3 * z.im * z.im)) + c.re;
- n.im = z.im * ((3 * z.re * z.re) - (z.im * z.im)) + c.im;
-
- return n;
- }
-
- /* // equivalent alternative function-- easier, but slower.
- {
- return ( cadd (cxpwri(z, 3), c) );
- }
- */
-
-
- void plot (short x, short y, Boolean isBlack)
- {
- if ( isBlack )
- {
- MoveTo (x0 + x, y0 + y);
- Line (0,0);
- }
- }
-
-
- complex computeZzero(short j, short k)
- {
- complex n;
-
- n.re = target.left + (incX * j);
- n.im = target.top + (incY * k);
- return n;
- }
-
-
- extended modSq(complex z)
- {
- return ( (z.re * z.re) + (z.im * z.im) );
- }
-
-
- void drawContents(WindowPtr w)
- {
- short j, k, n;
- complex z;
- EventRecord evt;
-
-
- EraseRect(&(w->portRect));
-
- if ( alreadyDrawn )
- CopyBits (&offScreen, &(display->portBits),
- &(offScreen.bounds), &(offScreen.bounds),
- srcCopy, nil);
-
- else
- {
- while ( GetNextEvent(mDownMask + keyDownMask, &evt) )
- {}; /* dump event queue */
-
- PenNormal();
- for ( j = 0; j < stepsX; ++j )
- {
- if ( EventAvail(mDownMask + keyDownMask, &evt) )
- break;
- for ( k = 0; k < stepsY; ++k )
- {
- z = computeZzero(j,k);
- for ( n = 0; n < 10; ++n )
- {
- z = generator(z);
- if ( (fabs(z.re) > 10.0) ||
- (fabs(z.im) > 10.0) ||
- (modSq(z) > 100.0) )
- break;
- }
- plot (j, k, ((fabs(z.re) < 10) || (fabs(z.im) < 10)) );
- }
- }
- alreadyDrawn = true;
- CopyBits (&(display->portBits), &offScreen,
- &(offScreen.bounds), &(offScreen.bounds),
- srcCopy, nil);
- SysBeep(1);
- }
- }
-
-
- /**** generic tool stuff ****/
-
-
- void doUpdate(WindowPtr w)
- {
- GrafPtr savePort;
-
- GetPort(&savePort);
- SetPort(w);
- ClipRect(&(w->portRect));
- BeginUpdate(w);
- drawContents(w);
- EndUpdate(w);
- SetPort(savePort);
- }
-
-
- void makeOffScreen() /* set up offscreen bitmap to store image */
- {
- Size sizeOfOff;
- short offRowBytes;
-
- offRowBytes = (((windowWidth - 1) / 16) + 1) * 2;
- sizeOfOff = windowHeight * offRowBytes;
-
- offScreen.baseAddr = (QDPtr) NewPtr(sizeOfOff);
- offScreen.rowBytes = offRowBytes;
- SetRect(&(offScreen.bounds), 0, 0, windowWidth, windowHeight);
- }
-
-
- void makeWindow()
- {
- Rect bounds;
-
- SetRect(&bounds, windowLeft, windowTop, windowLeft + windowWidth, windowTop + windowHeight);
- display = NewWindow(nil, &bounds, windowTitle, true, noGrowDocProc, (WindowPtr) -1, true, 0L);
- }
-
-
- void printWindow()
- {
- TPPrPort pport;
- THPrint hPrint;
- TPrStatus PrStatus;
- GrafPtr oldPort;
- Boolean notCancelled = true;
- Boolean drop;
-
- GetPort (&oldPort);
- PrOpen();
-
- SetFractEnable(true);
- SetFScaleDisable(true);
-
- hPrint = (THPrint) NewHandle(sizeof(TPrint));
- if (ResError())
- {
- printf ("Printing Error %d\n", ResError());
- SysBeep(1);
- PrClose();
- return;
- }
-
- drop = PrValidate(hPrint);
- notCancelled = PrJobDialog (hPrint);
-
- if (notCancelled)
- {
- pport = PrOpenDoc(hPrint, nil, nil);
- if ( PrError() == noErr )
- {
- PrOpenPage(pport, nil);
- if (PrError()==noErr)
- CopyBits (&offScreen, &(pport->gPort.portBits),
- &(offScreen.bounds), &(offScreen.bounds),
- srcCopy, nil);
- PrClosePage(pport);
- }
- PrCloseDoc(pport);
- }
- if ( ((**hPrint).prJob.bJDocLoop == bSpoolLoop)
- && (PrError() == noErr) )
- PrPicFile (hPrint, nil, nil, nil, &PrStatus);
-
- SetFractEnable(false);
- SetFScaleDisable(false);
-
- PrClose();
-
- SetPort (oldPort);
- }
-
-
- void mainLoop()
- {
- Boolean done = false;
- EventRecord theEvent;
- WindowPtr whichWindow;
- short part;
-
- while ( !done )
- {
- if ( GetNextEvent(everyEvent, &theEvent) )
- {
- switch ( theEvent.what )
- {
- case updateEvt:
- doUpdate(display);
- break;
-
- case mouseDown:
- part = FindWindow(theEvent.where, &whichWindow);
- if ( (whichWindow == display) && (part == inGoAway) )
- done = true;
- else
- SysBeep(1);
- break;
-
- case keyDown:
- if ( 'p' == (theEvent.message & charCodeMask) )
- printWindow();
- else
- SysBeep(1);
- break;
- }
- }
- }
- }
-
-
- void cleanUp()
- {
- DisposeWindow(display);
- DisposPtr((Ptr) offScreen.baseAddr);
- }
-
-
- int main (
- int argc, /* number of arguments */
- char *argv[], /* pointer to array of argument strings */
- char *envp[]) /* pointer to array of variable definitions */
- {
- #pragma unused (envp)
-
- InitGraf((Ptr) &qd.thePort);
- SetFScaleDisable(true);
- InitCursor();
-
- if ( argc != 7 )
- {
- printf ("### Wrong Number of Parameters ###\n");
- return 2;
- }
-
- c.re = atof(argv[1]);
- c.im = atof(argv[2]);
- target.top = atof(argv[3]);
- target.left = atof(argv[4]);
- target.bottom = atof(argv[5]);
- target.right = atof(argv[6]);
-
- x0 = (windowWidth - stepsX) / 2;
- y0 = (windowHeight - stepsY) / 2;
-
- incX = (target.right - target.left) / stepsX;
- incY = (target.bottom - target.top) / stepsY;
-
- alreadyDrawn = false;
-
- makeOffScreen();
- makeWindow();
- mainLoop();
- cleanUp();
-
- return 0;
- }
-